#ifndef __PACKETMANAGER_HPP_
#define __PACKETMANAGER_HPP_

#include <iostream>
#include <cstdlib>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/cast.hpp>

#include "common/network/BasicBuffer.hpp"

#define packet_mgr		network::PacketManager::getSingleton()

    namespace network
    {


        namespace packet
        {
            class BasicPacket;
        }

		class PacketManager
        {

            std::map<boost::uint16_t, packet::BasicPacket*> m_mPacket;
			static PacketManager*							m_singleton;

            PacketManager();

            ~PacketManager();

        public:

			bool checkPacketId( buffer::BasicBuffer* _packet );
			void registerPacket(boost::uint16_t _opcode, packet::BasicPacket* _packet);

            /**
             * @fn		getSingletonPtr()
             * @brief	Getter on the singleton
             * @return	The unique instance of the singleton
             */
            static PacketManager* getSingletonPtr()
            {
                if (m_singleton == NULL)
                    m_singleton = new PacketManager();
                return m_singleton;
            }

            /**
             * @fn		getSingleton()
             * @brief	Getter on the singleton
             * @return	The unique instance of the singleton
             */
            static PacketManager& getSingleton()
            {
                if (m_singleton == NULL)
                    m_singleton = new PacketManager();
                return *m_singleton;
            }

            /**
             * @fn		createSingleton()
             * @brief	Create the singleton
             * @return	The unique instance of the singleton
             */
            static PacketManager* createSingleton()
            {
                if (m_singleton == NULL)
                    m_singleton = new PacketManager();
                return m_singleton;
            }

            /**
             * @fn		destroySingleton()
             * @brief	Destroy the singleton
             */
            static void destroySingleton()
            {
			    if( m_singleton != NULL )
			        delete m_singleton;
                m_singleton = NULL;
            }

            // Receive a bytes array, and the size, then resolve the packet
            // doing a callback on the session

            template < class T >
            void resolve(T _session, boost::shared_ptr< std::vector<unsigned char> > data, size_t size)
            {
#if defined(_DEBUG) && defined(_OUTPUT)
                std::cout << " < Parser > resolving packet... " << std::endl;
#endif

                buffer::BasicBuffer* buf = buffer::BasicBuffer::make(data);

                

                // Get the opcode to identify packet
                std::map<boost::uint16_t, packet::BasicPacket*>::iterator it_packet = m_mPacket.find(buf->getId());
                if (it_packet == m_mPacket.end())
                {
#if defined(_DEBUG) && defined(_OUTPUT)
                    std::cout << "unknown packet" << std::endl;
#endif
					delete buf;
                    return;
                }
                else
                {
#if defined(_DEBUG) && defined(_OUTPUT)
                    std::cout << "packet found: 0x0" << buf->getId() << std::endl;
#endif
                }

                it_packet->second->handle(_session, *buf);
				delete buf;

                return;
            }
        };

    } //  namespace   network

#endif // __PACKETMANAGER_HPP_
